package io.netty.example.fep.netty.common;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

import static io.netty.example.fep.netty.common.FepProtocolMsg.Constants.*;

/**
 * Description：
 * 自定义msg（header+length+content）解码器
 *
 * @author : chenjie03@imdada.cn
 * Date: 2020/5/26
 * Time: 13:48
 */
public class FepProtocolDecoder extends LengthFieldBasedFrameDecoder {

    /**
     * 自定义配置
     *
     * @param maxFrameLength      帧的最大长度
     * @param lengthFieldOffset   length字段偏移的地址
     * @param lengthFieldLength   length字段所占的字节长
     * @param lengthAdjustment    修改帧数据长度字段中定义的值，可以为负数 因为有时候我们习惯把头部记入长度,若为负数,则说明要推后多少个字段
     * @param initialBytesToStrip 解析时候跳过多少个长度
     * @param failFast            为true，当frame长度超过maxFrameLength时立即报TooLongFrameException异常，为false，读取完整个帧再报异
     */
    public FepProtocolDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
    }

    /**
     * 默认配置
     */
    public FepProtocolDecoder() {
        super(MAX_FRAME_LENGTH, LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP, false);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        //父类中解析出所有，并非只有body部分
        in = (ByteBuf) super.decode(ctx, in);

        if (in == null) {
            return null;
        }
        //1个byte的标志位，4个byte的长度(int)
        if (in.readableBytes() < 5) {
            throw new Exception("字节数不足");
        }
        //读取type字段
        byte type = in.readByte();

        //读取length字段
        int length4Body = in.readInt();

        if (in.readableBytes() < length4Body) {
            throw new Exception("标记的长度不符合实际长度(半包)");
        }
        //读取body
        byte[] bytes4Body = new byte[in.readableBytes()];
        in.readBytes(bytes4Body);
        return new FepProtocolMsg(type, new String(bytes4Body, "UTF-8"));
    }
}
